1.Window对象

  • BOM(浏览器对象模型)

    • 是一个全局对象,JavaScript中的顶级对象
    • 例如document、alert()、console.log()都是window属性
    • 所有通过var定义在全局作用域中的变量、函数都会编程window对象的属性和方法
    • window对象下的属性和方法调用的时候可以省略window
  • 定时器——延时函数

    • 语法

      setTimeout(回调函数,等待的毫秒数)
      
    • 清楚延时函数

      let timer = setTimeout(回调函数,等待的毫秒数)
      clearTimeout(timer)
      
    • 注意点

      • 延时器需要等待,所以后面代码会先执行
      • 每一次调用延时器都会产生一个新的延时器
    setTimeout(function(){
        console.log("只运行一次")
    },3000)
    
  • JS执行机制

    • JavaScript语言的一大特点就是单线程
    • 为解决问题,利用多核 CPU 的计算能力,H5提出 Web Worker标准,允许 JS 脚本创建多个线程,出现了同步异步
    • 同步任务
      • 同步任务都是在主线程上执行,形成一个执行栈
    • 异步任务
      • 普通事件,例如:click resize等
      • 资源加载,例如:load,error等
      • 定时器,例如:setInterval、setTimeout等
      • 异步任务相关添加到任务队列中

image-20230810203500688.png

image-20230810203507346.png

由于主线程不断的重复获得任务、执行任务、再获得任务、再执行,所以这种机制被称为事件循环

  • location对象

    • location的数据类型是对象,它拆分保存了 URL地址的各个组成部分
    • 常用属性和方法
      • href:获取完整的 URL 地址,对其赋值时用于地址的跳转
      • search:获取地址中携带的参数,符号 ? 后面部分
      • hash:获取地址中的哈希值,符号 # 后面部分
      • reload():用来刷新当前页面,传入参数 true 表示强制刷新
    • 案例

image-20230810203514698.png

  <body>
      <a href="https://www.baidu.com">支付成功<span>5</span>秒后跳转页面</a>
      <script>
          const a = document.querySelector("a")
          num = 5
          let timeId = setInterval(function(){
              num--
              a.innerHTML = `支付成功<span>${num}</span>秒后跳转页面`
              if(num == 0){
                  clearInterval(timeId)
                  location.href = "https://www.baidu.com"
              }
          },1000)
      </script>
  </body>
  • navigator对象

    • 数据类型为对象,该对象下记录了浏览器自身的相关信息
    • 通过 userAgent 检测浏览器版本及平台
    // 检测 userAgent(浏览器信息)
    !(function () {
        const userAgent = navigator.userAgent
        // 验证是否为Android或iPhone
        const android = userAgent.match(/(Android);?[\s\/]+([\d.]+)?/)
        const iphone = userAgent.match(/(iPhone\sOS)\s([\d_]+)/)
        // 如果是Android或iPhone,则跳转至移动站点
        if (android || iphone) {
            location.href = 'http://m.itcast.cn' 
        }
    })()
    
  • history对象

    • 数据类型为对象,主要管理历史记录,该对象与浏览器地址栏的操作相对应,例如 前进、后退、历史记录等
    • 属性和方法

image-20230810203524651.png

2.本地存储

  • 概述

    • 数据存储在用户浏览器
    • 设置、读取方便,甚至页面刷新不丢失数据
    • 容量较大,sessionStorage和localStorage 约 5M 左右
  • 本地存储类型——localStorage

    • 作用:可以将数据永久存储在本地(用户的电脑),除非手动删除,否则关闭页面也会存在

    • 特性

      • 可以多窗口(页面)共享
      • 键值对的形式存储
    • 语法

      • 存储/更改
      localStorage修改数据 改(与增一致,存在则改,不存在则为增)
      localStorage.setItem("name", "马浩楠")
      
      • 获取
      console.log(localStorage.getItem("name"))
      
      • 删除
      localStorage.removeItem("name")
      
    • 浏览器查看位置

image-20230810203537584.png

  • 本地存储——sessionStorage

    • 生命周期为关闭浏览器窗口
    • 其它与localStorage一致
  • 存储复杂数据类型

    • 需要将复杂数据类型转换为JSON字符串,存储到本地
    • 对象转JSON
    JSON.stringify(对象)
    
    • JSON转对象
    JSON.parse(json字符串)
    
    • 实例
    <script>
        const obj = {
            name: "马浩楠",
            age: 22
        }
        localStorage.setItem("obj",obj)
        console.log(localStorage.getItem("obj")) // [object Object]这种方式无法存储复杂数据类型 
    
        // 将复杂数据类型转换为json字符串进行存储
        localStorage.setItem("obj",JSON.stringify(obj))
    
        console.log(localStorage.getItem("obj")) // {"name":"马浩楠","age":22}
        // 将json字符串转换为对象
        console.log(JSON.parse(localStorage.getItem("obj")))
    </script>
    

3.综合案例

  • 数组中的map方法
    • 处理数据,并且返回新的数组
const arr = ["red","blue","green"]
// 1.map方法:放回新的数组
const newArr = arr.map(function(ele,index){
    console.log(ele) // 数组元素
    console.log(index) // 数组索引
    return ele + "颜色"
})
  • 数据中的join方法

    • 用于吧数组中的所有元素转换为一个字符串

    • 参数:数组元素是通过参数里面指定的分隔符进行分割的

// 2.join方法:吧数组转换为字符串
// 参数为空则分隔符为逗号
console.log(newArr.join()) // red颜色,blue颜色,green颜色
console.log(newArr.join("")) // red颜色blue颜色green颜色
  • 综合案例

image-20230810203550274.png

<body>
  <h1>新增学员</h1>
  <form class="info" autocomplete="off">
    姓名:<input type="text" class="uname" name="uname" />
    年龄:<input type="text" class="age" name="age" />
    性别:
    <select name="gender" class="gender">
      <option value="男"></option>
      <option value="女"></option>
    </select>
    薪资:<input type="text" class="salary" name="salary" />
    就业城市:<select name="city" class="city">
      <option value="北京">北京</option>
      <option value="上海">上海</option>
      <option value="广州">广州</option>
      <option value="深圳">深圳</option>
      <option value="曹县">曹县</option>
    </select>
    <button class="add">录入</button>
  </form>

  <h1 class="info" style="text-align: right;">共有数据<span style="text-align:right;color: red;"></span></h1>
  <table>
    <thead>
      <tr>
        <th>学号</th>
        <th>姓名</th>
        <th>年龄</th>
        <th>性别</th>
        <th>薪资</th>
        <th>就业城市</th>
        <th>操作</th>
      </tr>
    </thead>
    <tbody>
      <!-- 
        <tr>
          <td>1001</td>
          <td>欧阳霸天</td>
          <td>19</td>
          <td>男</td>
          <td>15000</td>
          <td>上海</td>
          <td>
            <a href="javascript:">删除</a>
          </td>
        </tr> 
        -->
    </tbody>
  </table>
  <script>
    // 参考数据
    // let data = [{
    //   stuId: 1001,
    //   uname: '欧阳霸天',
    //   age: 19,
    //   gender: '男',
    //   salary: '20000',
    //   city: '上海',
    // }]
    let data = JSON.parse(localStorage.getItem("data"))
    const uname = document.querySelector(".uname")
    const age = document.querySelector(".age")
    const gender = document.querySelector(".gender")
    const salary = document.querySelector(".salary")
    const city = document.querySelector(".city")
    // 添加
    const info = document.querySelector(".info")
    info.addEventListener("submit", function () {
      if(uname.value && age.value && gender.value && salary.value && city.value){
        const obj = {
          stuId: data.length ? +data[length-1].stuId + 1 : 1,
          uname: uname.value,
          age: age.value,
          gender: gender.value,
          salary: salary.value,
          city: city.value
        }
        data.push(obj)
        // 存储到本地
        localStorage.setItem("data", JSON.stringify(data))

        render()
      }else{
        alert("输入不能为空")
      }
    })
    // 渲染
    const tbody = document.querySelector("tbody")
    render()

    function render() {
      tbody.innerHTML = ''
      // 是空则为空数组
      data = data ? JSON.parse(localStorage.getItem("data")) : []
      // 几条数据
      document.querySelector("span").innerHTML = `${data.length}`

      // 利用map方法,将数据返回为tr形式
      const newData = data.map(function (ele,index) {
        return `
        <tr>
          <td>${ele.stuId}</td>
          <td>${ele.uname}</td>
          <td>${ele.age}</td>
          <td>${ele.gender}</td>
          <td>${ele.salary}</td>
          <td>${ele.city}</td>
          <td class='delete'>
            <a href="javascript:" data-id=${index}>删除</a>
          </td>
        </tr>
        `
      })
      // 将map方法进行处理过后的数组转为字符串形式来渲染tbody
      tbody.innerHTML = newData.join("")
    }
    // 删除
    tbody.addEventListener("click", function (e) {
      if (e.target.tagName == "A") {
        if (window.confirm("确定删除吗?")) {
          for (let i = 0; i < data.length; i++) {
            if (i == e.target.dataset.id) {
              data.splice(i, 1)
              localStorage.setItem("data", JSON.stringify(data))
            }
          }
        }
      }
      render()
    })
  </script>
</body>

4.正则表达式

  • 语法

    const 变量名 = /表达式/
    
    • 判断是否有符合规则的字符串:

      • test()方法:用来查看正则表达式于指定的字符串是否匹配
      • 返回true / false
    • 检索符合规则的字符串

      • exec()方法:在一个指定字符串中执行一个搜索匹配
      • 匹配成功,exec()方法返回一个数组,否则返回null
    const str = "正在学习JS,赚钱学习路程中..."
    // 定义规则
    const reg = /学习/
    // 匹配:返回true/false
    console.log(reg.test(str))
    // 匹配exec:返回数组/null
    console.log(reg.exec(str))
    
  • 元字符

    • 边界符(表示位置,开头和结尾)

image-20230810203631663.png

  • 量词(表示重复次数)

image-20230810203639877.png

注意逗号左右两则不要出现空格

  • 字符类

    • []:比如 [a-z] 匹配小写字母
    • . :匹配换行符之外的任何单个字符
    • 预定义:某些常见规模的简写方式

image-20230810203647902.png

  • 案例

image-20230810203653904.png

<input type="text">
    <span></span>
<script>
    const input = document.querySelector("input")
    const span = document.querySelector("span")
    input.addEventListener("blur",function(){
        const regex = /^[a-zA-Z0-9-_]{6,16}$/
        span.className = ""
        span.innerHTML = ""
        if(!regex.test(input.value)){
            span.innerText = "只能输入6~16位字符"
            span.classList.add("error")
        }else{
            span.innerText = "输入正确"
            span.classList.add("right")
        }
    })
</script>
  • 修饰符

    /表达式/修饰符
    
    • i 是单词 ignore 的缩写,正则匹配时字母不区分大小写

    • g 是单词 global 的缩写,匹配所有满足正则表达式的结果

    • replcae 替换

    字符串.replace(/正则表达式/,"替换的文本")
    
    // i:ignore忽略大小写
    console.log(/^java$/.test("java"))  // true
    console.log(/^java$/.test("JAVA"))  // false
    console.log(/^java$/i.test("Java")) // true
    
    // replace使用正则   g:全局查找    也可两个都写
    const str = "Python是一门编程语言,Python is very nice"
    console.log(str.replace(/python/gi,"Java"))
    
  • 案例

image-20230810203701441.png

<body>
    <textarea name="" id="" cols="30" rows="10"></textarea>
    <button>发布</button>
    <div></div>
    <script>
        const text = document.querySelector("textarea")
        const btn = document.querySelector("button")
        const div = document.querySelector("div")
        btn.addEventListener("click",function(){
            div.innerHTML = text.value.replace(/激情/g,"**")
        })
    </script>
</body>

5.综合案例

image-20230810203709041.png

// 验证码部分
const code = document.querySelector(".code")
let isTrue = true
code.addEventListener("click",function(){

    if(isTrue){
        let i = 5
        code.innerHTML = `0${i}后重新获取`
        let timeId = setInterval(function(){
            isTrue = false
            i --
            code.innerHTML = `0${i}后重新获取`
            if(i == 0){
                isTrue = true
                code.innerHTML = "重新获取"
                clearInterval(timeId)
            }

        },1000)
        }
})

// 表单验证部分
// 1.名称
const username = document.querySelector("input[name='username']")
username.addEventListener("change",confirmUserName)
function confirmUserName(){
    if(!/^[a-zA-Z0-9-_]{6,10}$/.exec(username.value.trim())){
        username.nextElementSibling.innerHTML = "昵称长度为6-10个字符"
        return false
    }
    username.nextElementSibling.innerHTML = ""
    return true
}
// 2.手机号
const phone = document.querySelector("input[name='phone']")
phone.addEventListener("change",confirmPhone)
function confirmPhone(){
    if(!/^1(3\d|4[5-9][5[0-35-9][6[567][7[0-8][8\d|9[0-35-9])\d{8}$/.test(phone.value.trim())){
        phone.nextElementSibling.innerHTML = "请输入正确的手机号"
        return false
    }
    phone.nextElementSibling.innerHTML = ""
    return true
}
// 3.验证码
const inputCode = document.querySelector("input[name='code']")
inputCode.addEventListener("change",confirmCode)
function confirmCode(){
    if(!/^\d{6}/.test(inputCode.value.trim())){
        inputCode.nextElementSibling.innerHTML = "验证码错误"
        return false
    }
    inputCode.nextElementSibling.innerHTML = ""
    return true
}
// 4.密码
const pwd = document.querySelector("input[name='password']")
pwd.addEventListener("change",confirmPwd)
function confirmPwd(){
    if(!/^[a-zA-Z0-9-_]{6,20}$/.test(pwd.value.trim())){
        pwd.nextElementSibling.innerHTML = "设置6-20位字母、数字和符号组合"
        return false
    }
    pwd.nextElementSibling.innerHTML = ""
    return true
}
// 5.确认密码
const confirmAgainPwd = document.querySelector("input[name='confirm']")
confirmAgainPwd.addEventListener("change",confirmRepwd)
function confirmRepwd(){
    if(confirmAgainPwd.value.trim() == pwd.value.trim()){
        confirmAgainPwd.nextElementSibling.innerHTML = ""
        return true
    }
    confirmAgainPwd.nextElementSibling.innerHTML = "两次密码不一致"
    return false
}
// 确认协议
const icon = document.querySelector(".icon-queren")
icon.addEventListener("click",function(){
    this.classList.toggle("icon-queren2")
})
// 提交
const form = document.querySelector(".xtx-form")
form.addEventListener("submit",function(e){
    console.log(11)
    if(!icon.classList.contains("icon-queren2")){
        alert("请勾选同意协议")
        e.preventDefault()
    }
    if(!confirmUserName()) e.preventDefault()
    if(!confirmPhone()) e.preventDefault()
    if(!confirmCode()) e.preventDefault()
    if(!confirmPwd()) e.preventDefault()
    if(!confirmRepwd()) e.preventDefault()
})

6.阶段案例

image-20230810203723072.png

const tab_nav = document.querySelector(".tab-nav")
const pane = document.querySelectorAll(".tab-pane")
tab_nav.addEventListener("click",function(e){
    if(e.target.tagName === "A"){
        tab_nav.querySelector(".active").classList.remove("active")

        e.target.classList.add("active")
        // 将div都先隐藏
        for(let i = 0;i<pane.length;i++){
            pane[i].style.display = "none"
        }
        pane[e.target.dataset.id].style.display = "block"
    }
})
// 登录
const form = document.querySelector("form")
const agree = document.querySelector("input[name='agree']")
const userName = document.querySelector("input[name='username']")
form.addEventListener("submit",function(e){
    e.preventDefault()
    if(!agree.checked){

        return alert("请先勾选同意协议!")
    }
    // 将用户名存储到本地存储
    localStorage.setItem("userName",userName.value)
    // 跳转页面
    window.location.href = "./index.html"
})

image-20230810203731152.png

const firstLi = document.querySelector("ul[class='xtx_navs'] li:first-child")
const secondLi = firstLi.nextElementSibling
// 渲染
function render(){
    const userName = localStorage.getItem("userName")
    if(userName){
        firstLi.innerHTML = `<a href="javascript:;"><i class="iconfont icon-user">${userName}</i></a>`
        secondLi.innerHTML = '<a href="javascript:;">退出登录</a>'
    }else{
        firstLi.innerHTML = `<a href="./login.html">请先登录</a>`
        secondLi.innerHTML = '<a href="./register.html">免费注册</a>'
    }

}
render()
secondLi.addEventListener("click",function(){
    localStorage.removeItem("userName")
    render()
})

7.Web APIS综合案例

image-20230810203737433.png

(function(){
    const sticky = document.querySelector(".sticky")
    const header = document.querySelector(".xtx_header .wrapper")
    window.addEventListener("scroll",function(){
        const n = document.documentElement.scrollTop
        sticky.style.top = n >= header.offsetTop ? "0px" : "-80px"
    })
})();

image-20230810203744010.png

// 图片
(function(){
    const ul = document.querySelector(".small ul")
    const img = document.querySelector(".middle img")
    // mouseenter 没有冒泡   mouseover存在
    ul.addEventListener("mouseover",function(e){

        if(e.target.tagName === "IMG"){
            this.querySelector(".active").classList.remove("active")

            e.target.parentNode.classList.add("active")

            img.src = e.target.src

            large.style.backgroundImage = `url(${e.target.src})`
        }
    })
    // 回到顶部
    const backTop = document.querySelector(".backTop")
    backTop.addEventListener("click",function(){
        document.documentElement.scrollTo(0,0)
    })
})();

放大镜效果

①:鼠标经过对应小盒子,左侧中等盒子显示对应中等图片

②: 鼠标经过中盒子,右侧会显示放大镜效果的大盒子

③: 黑色遮罩盒子跟着鼠标来移动

④: 鼠标在中等盒子上移动,大盒子的图片跟着显示对应位置

解析

③: 黑色遮罩盒子跟着鼠标来移动

  1. 先做鼠标经过 中等盒子,显示隐藏 黑色遮罩 的盒子

  2. 让黑色遮罩跟着鼠标来走, 需要用到鼠标移动事件 mousemove

  3. 让黑色盒子的移动的核心思想:不断把鼠标在中等盒子内的坐标给黑色遮罩层 let top 值,这样遮罩层就可以跟着移动了

    • 需求

      • 我们要的是 鼠标在 中等盒子内的坐标, 没有办法直接得到
      • 得到1: 鼠标在页面中的坐标
      • 得到2: 中等盒子在页面中的坐标
    • 算法

      • 得到鼠标在页面中的坐标 利用事件对象的 pageX
      • 得到middle中等盒子在页面中的坐标 middle.getBoundingClientRect()
      • 鼠标在middle 盒子里面的坐标 = 鼠标在页面中的坐标 - middle 中等盒子的坐标
      • 黑色遮罩层不断得到 鼠标在middle 盒子中的坐标 就可以移动起来了
      注意 y坐标特殊,需要减去 页面被卷去的头部
      
      为什么不用 box.offsetLet 和 box.offsetTop 因为这俩属性跟带有定位的父级有关系,
      
      很容被父级影响,而getBoundingClientRect() 不受定位的父元素的影响
      
    • 限定遮罩的盒子只能在middle 内部移动,需要添加判断

      • 限定水平方向 大于等于0 并且小于等于 400
      • 限定垂直方向 大于等于0 并且小于等于 400
    • 遮罩盒子移动的坐标:

      • 声明一个 mx 作为移动的距离
      • 水平坐标 x 如果 小于等于100 ,则移动的距离 mx 就是 0 不应该移动
      • 水平坐标 如果 大于等于100 并且小于300,移动的距离就是 mx - 100 (100是遮罩盒子自身宽度的一半)
      • 水平坐标 如果 大于等于300,移动的距离就是 mx 就是200 不应该在移动了
      • 其实我们发现水平移动, 就在 100 ~ 200 之间移动的
      • 垂直同理
    let mx = 0, my = 0;
    if (x <= 100) mx = 0
    if (x > 100 && x < 300) mx = x - 100
    if (x >= 300) mx = 200
    
    if (y <= 100) my = 0
    if (y > 100 && y < 300) my = y - 100
    if (y >= 300) my = 200
    
    • 大盒子图片移动的计算方法:
      • 中等盒子是 400px 大盒子 是 800px 的图片
      • 中等盒子移动1px, 大盒子就应该移动2px, 只不过是负值
    large.style.backgroundPositionX = - 2 * mx + 'px'
    large.style.backgroundPositionY = - 2 * my + 'px'
    
const small = document.querySelector(".small")
const middle = document.querySelector(".middle")
const large = document.querySelector(".large")
// 鼠标经过中等盒子显示大盒子
middle.addEventListener("mouseenter",show)
middle.addEventListener("mouseleave",hide)

let timerId = null
function show(){
    clearTimeout(timerId)
    large.style.display = "block"
}
function hide(){
    timerId = setTimeout(function(){
        large.style.display = "none"
    },200)
}

// 鼠标经过大盒子,显示隐藏 大盒子
large.addEventListener("mouseenter",show)
large.addEventListener("mouseout",hide)
// 放大镜:黑色遮罩
const layer = document.querySelector(".layer")
middle.addEventListener("mousemove",function(){
    layer.style.display = "block"
})
middle.addEventListener("mouseleave",function(){
    layer.style.display = "none"
})
// 放大镜:移动黑色遮罩
middle.addEventListener("mousemove",function(e){
    // 鼠标在middle 盒子里面的坐标 = 鼠标在页面中的坐标(e.pageX/e.pageY) - middle中等盒子的坐标(getBoundingClientRect())
    let x = e.pageX - middle.getBoundingClientRect().left
    let y = e.pageY - middle.getBoundingClientRect().top - document.documentElement.scrollTop
    //layer.style.left = x >= 200 ? "200px" :x + "px"
    //layer.style.top = y >= 200 ? "200px" : y + "px"

    let mx = 0 , my = 0
    if(x <= 100) mx = 0
    if(x > 100 && mx < 300) mx = x - 100
    if(x >= 300) mx = 200

    if(y <= 100) my = 0
    if(y > 100 && my < 300) my = y - 100
    if(y >= 300) my = 200

    layer.style.left = mx + "px"
    layer.style.top = my + "px"

    // 大盒子的背景图片要跟随中等盒子移动 存在关系是2倍
    large.style.backgroundPositionX = -2 * mx +"px"
    large.style.backgroundPositionY = -2 * my +"px"
})

image-20230810203801369.png

image-20230810203809542.png

// 点击模块
(function(){
    const size = document.querySelector("#size")
    size.addEventListener("click",function(e){
        if(e.target.tagName === "SPAN"){
            size.querySelector(".active").classList.remove("active")

            e.target.classList.add("active")
        }
    })
    // 加减物品数量
    const num = document.querySelector(".num")
    const decrease = num.children[0]
    const number = num.children[1]
    const increase = num.children[2]
    decrease.addEventListener("click",function(){
        if(number.value == 1){
            this.disabled = true
            return
        }
        number.value -= 1
    })
    increase.addEventListener("click",function(){
        number.value = +number.value +1
    })
    // tab切换
    const tab = document.querySelector(".tab-head")
    const panes = document.querySelectorAll(".cont .tab-pane")
    tab.addEventListener("click",function(e){
        if(e.target.tagName === "A"){
            for(let i = 0;i<panes.length;i++){
                panes[i].style.display = "none"
            }
            panes[e.target.dataset.id].style.display = "block"
        }
    })
})();

results matching ""

    No results matching ""